﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Plists;
using System.IO;

namespace TapTapServer
{
    public static class plistManager
    {
        static public TrackInfo readPlist(Stream plistStream)
        {
            BinaryPlistReader reader = new BinaryPlistReader();
            IDictionary trackInfoGraph = reader.ReadObject(plistStream);
            return makeTrackInfo(trackInfoGraph);
        }
        static public TrackInfo readPlist(string plistPath)
        {
            BinaryPlistReader reader = new BinaryPlistReader();
            IDictionary trackInfoGraph = reader.ReadObject(plistPath);
            return makeTrackInfo(trackInfoGraph);
        }

        static private TrackInfo makeTrackInfo(IDictionary trackInfoGraph)
        {
            TrackInfo track = new TrackInfo();
            track.audioFileDuration = (string)trackInfoGraph["audioFileDuration"];
            track.availableDifficultyLevels = convertToIntArray((object[])trackInfoGraph["availableDifficultyLevels"]);
            track.kTTRBandLink = (string)trackInfoGraph["kTTRBandLink"];
            track.kTTRDownloadableItemSubtitleKey = (string)trackInfoGraph["kTTRDownloadableItemSubtitleKey"];
            track.kTTRDownloadableItemTitleKey = (string)trackInfoGraph["kTTRDownloadableItemTitleKey"];
            track.kTTRDownloadableItemUniqueIdentifierKey = (string)trackInfoGraph["kTTRDownloadableItemUniqueIdentifierKey"];
            track.kTTRGenre = (string)trackInfoGraph["kTTRGenre"];
            track.kTTRiTunesLink = (string)trackInfoGraph["kTTRiTunesLink"];
            track.kTTRTrackDecryptionKey = (byte[])trackInfoGraph["kTTRTrackDecryptionKey"];
            track.levelThemes = (Dictionary<object, object>)trackInfoGraph["levelThemes"];
            track.previewURL = (string)trackInfoGraph["previewURL"];
            track.price = (string)trackInfoGraph["price"];
            track.row_id = (string)trackInfoGraph["row_id"];
            track.themeName = (string)trackInfoGraph["themeName"];
            track.kTTRDownloadableItemCommandsKey = (object[])trackInfoGraph["kTTRDownloadableItemCommandsKey"];
            track.kTTRDownloadableItemVersionKey = (string)trackInfoGraph["kTTRDownloadableItemVersionKey"];


            //these werent in the sample tracks I used for testing, but they may be in other more recent tracks
            if (trackInfoGraph.Contains("type"))
            {
                track.type = (short)trackInfoGraph["type"];
            }
            else
            {
                track.type = (short)1;
            }
            if (trackInfoGraph.Contains("columnCountPerLevel"))
            {
                track.columnCountPerLevel = (Dictionary<object, object>)trackInfoGraph["columnCountPerLevel"];
            }
            else
            {
                track.columnCountPerLevel = new Dictionary<object, object>();
                track.columnCountPerLevel.Add("1", "3");
                track.columnCountPerLevel.Add("2", "3");
                track.columnCountPerLevel.Add("3", "3");
                track.columnCountPerLevel.Add("4", "3");
            }

            if (trackInfoGraph.Contains("is_hires_hero"))
            {
                track.is_hires_hero = ((Int16)trackInfoGraph["is_hires_hero"]).ToString();
            }
            else
            {
                track.is_hires_hero = "0";
            }
            return track;
        }

        static private string[] convertToStringArray(object[] inArray)
        {
            string[] retVal = new string[inArray.Length];
            for (int i = 0; i < inArray.Length; i++)
            {
                retVal[i] = (string)inArray[i];
            }

            return retVal;
        }
        static private int[] convertToIntArray(object[] inArray)
        {
            int[] retVal = new int[inArray.Length];
            for (int i = 0; i < inArray.Length; i++)
            {
                retVal[i] = Convert.ToInt32(inArray[i]);
            }

            return retVal;
        }
    }

    public class TrackInfo
    {
        public int[] availableDifficultyLevels { get; set; }
        public string kTTRBandLink { get; set; }

        public string kTTRDownloadableItemSubtitleKey { get; set; }
        public string kTTRDownloadableItemTitleKey { get; set; }

        public string kTTRDownloadableItemUniqueIdentifierKey { get; set; }
        public string kTTRGenre { get; set; }

        public byte[] kTTRTrackDecryptionKey { get; set; }
        public string kTTRiTunesLink { get; set; }

        public string previewURL { get; set; }
        public string price { get; set; }
        public string row_id { get; set; }

        public string themeName { get; set; }
        public Int16 type { get; set; }

        public Dictionary<object, object> levelThemes { get; set; }

        public string audioFileDuration { get; set; }

        public object[] kTTRDownloadableItemCommandsKey { get; set; }

        public string kTTRDownloadableItemVersionKey { get; set; }

        public Dictionary<object, object> columnCountPerLevel { get; set; }

        public string is_hires_hero { get; set; }
        //---
        private string template;

        public string makeTemplate()
        {
            //read in the song template
            template = File.ReadAllText(Path.Combine(Settings.Instance.ServerRootPath, "songInfo.template"));

            setTValue("[row_id]", row_id);
            setTValue("[audioFileDuration]", audioFileDuration);
            setTValue("[kTTRDownloadableItemSubtitleKey]", kTTRDownloadableItemSubtitleKey);
            setTValue("[kTTRDownloadableItemTitleKey]", kTTRDownloadableItemTitleKey);
            setTValue("[kTTRDownloadableItemUniqueIdentifierKey]", kTTRDownloadableItemUniqueIdentifierKey);
            setTValue("[themeName]", themeName);
            setTValue("[is_hires_hero]", is_hires_hero);
            setTValue("[kTTRiTunesLink]", kTTRiTunesLink);

            //dont worry about amazon, They'll get over it
            //setTValue("[kTTRAmazonLink]", kTTRAmazonLink);
            //setTValue("[kTTRAmazonAlbumASIN]", kTTRAmazonAlbumASIN);

            setTValue("[kTTRBandLink]", kTTRBandLink);
            setTValue("[kTTRGenre]", kTTRGenre);
            setTValue("[columnCountPerLevel]", makeColumnCountPerLevel());

            //TODO This bit is broken... not sure if it is really that important though. I will hard-wire it in the template
            //setTValue("[kTTRTrackDecryptionKey]", Convert.ToString(kTTRTrackDecryptionKey)); //<--Check this
            setTValue("[kTTRDownloadableItemCommandsKey]", makekTTRDownloadableItemCommandsKey());
            setTValue("[kTTRDownloadableItemIconURLStringKey]", (new Uri(Settings.ContentAddress, "smIcon.png")).ToString()); //hardwire this for the time being, should be set at runtime
            setTValue("[previewURL]", previewURL);
            setTValue("[kTTRDownloadableItemVersionKey]", kTTRDownloadableItemVersionKey);
            setTValue("[levelThemes]", makeLevelThemes());
            setTValue("[availableDifficultyLevels]", makeAvailableDifficultyLevels());
            setTValue("[price]", price);
            setTValue("[type]", type.ToString());

            //Console.WriteLine(template);
            fixAMPs();

            
            return template;
        }
        private void setTValue(string key, string value)
        {
            template = template.Replace(key, value);
        }


        private string makeColumnCountPerLevel()
        {
            string retVal = "";
            foreach (object key in columnCountPerLevel.Keys)
            {
                retVal += "<key>" + (string)key + "</key>";
                retVal += "<string>" + (string)columnCountPerLevel[key] + "</string>";
                retVal += "\n";
            }

            return retVal;
        }
        private string makekTTRDownloadableItemCommandsKey()
        {
            string retVal = "";
            foreach (Dictionary<object, object> fileInfo in kTTRDownloadableItemCommandsKey)
            {
                retVal += "<dict>\n";
                foreach (string key in fileInfo.Keys)
                {
                    retVal += "<key>" + key + "</key>";
                    if (key == "kTTRDownloadableItemSourceURLKey")
                    {
                        //patch the file
                        string origFile = (string)fileInfo[key];
                        //get the origional file name:
                        string origName = origFile.Substring(origFile.LastIndexOf("/") + 1); //TODO: do this with URIs
                        if (origName.Contains("&")) origName = origName.Substring(0, origName.IndexOf("&"));
                        string filetype = origName.Substring(origName.IndexOf(".")); //TODO: doth this with Path or URIs

                        if (origName.EndsWith("ttrTheme.zip"))
                        {
                            string versionKey = (string)fileInfo["kTTRDownloadableItemVersionKey"];
                            origName = origName.Substring(0, origName.IndexOf("."));
                            retVal += "<string>" + (new Uri(Settings.ThemesAddress, origName + "Bundle/v" + versionKey + "/" + origName + filetype)) + "</string>";
                        }
                        else
                        {
                            retVal += "<string>" + (new Uri(Settings.TracksAddress,  kTTRDownloadableItemUniqueIdentifierKey + "/" + origName)) + "</string>";
                        }
                    }
                    else if (key == "kTTRDownloadableItemEstimatedSizeKey")
                    {
                        //the type needs to to <integer>
                        retVal += "<integer>" + fileInfo[key] + "</integer>";
                    }
                    else
                    {
                        //write it as a string
                        retVal += "<string>" + fileInfo[key] + "</string>";
                    }
                    retVal += "\n";
                }
                retVal += "</dict>\n";
            }

            return retVal;
        }
        private string makeLevelThemes()
        {
            string retVal = "";
            foreach (object key in levelThemes.Keys)
            {
                retVal += "<key>" + (string)key + "</key>";
                retVal += "<string>" + (string)levelThemes[key] + "</string>";
                retVal += "\n";
            }

            return retVal;
        }
        private string makeAvailableDifficultyLevels()
        {
            string retVal = "";
            foreach (object value in availableDifficultyLevels)
            {
                retVal += "<integer>" + Convert.ToInt32(value) + "</integer>\n";
            }
            return retVal;
        }
        private void fixAMPs()
        {
            template = template.Replace("&", "&amp;");
            template = template.Replace("\'", "&apos;");
            template = template.Replace("\"", "&quot;");
        }
    }
}
